home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue48 / XML / XmlClasses.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1999-06-26  |  21.9 KB  |  842 lines

  1. unit XmlClasses;
  2.  
  3. interface
  4.  
  5. uses Classes, SysUtils;
  6.  
  7. type
  8.   TXmlNodeType = (xntDocument, xntElement, xntText,
  9.       xntComment, xntCDATASection);
  10.  
  11. const
  12.   XmlNodeNames: array[xntDocument..xntCDATASection] of String =
  13.       ('#document', '', '#text', '#comment', '#cdata-section');
  14.  
  15. type
  16.   EXmlDError = class(Exception);
  17.  
  18.   TXmlName = String;
  19.  
  20.   TXmlDDocument = class;
  21.   TXmlDStructureNode = class;
  22.   TXmlDElement = class;
  23.   TXmlDCDATASection = class;
  24.   TXmlDComment = class;
  25.   TXmlDText = class;
  26.   TXmlDAttrList = class;
  27.  
  28.   TXmlDNode = class(TPersistent)
  29.     private
  30.       FPreviousSibling: TXmlDNode;
  31.       FNextSibling:     TXmlDNode;
  32.       FParentNode:      TXmlDStructureNode;
  33.       FNodeType:        TXmlNodeType;
  34.     protected
  35.       function GetFirstChild: TXmlDNode; virtual;
  36.       function GetLastChild: TXmlDNode; virtual;
  37.       function GetOwnerDocument: TXmlDDocument;
  38.       function GetNodeName: TXmlName; virtual;
  39.       function GetNodeValue: String; virtual;
  40.       procedure SetNodeName(const Value: TXmlName); virtual;
  41.       procedure SetNodeValue(const Value: String); virtual;
  42.       function GetLevel: Integer;
  43.       procedure WriteToStream(Stream: TStream;
  44.           FormattedForPrint: Boolean); virtual; abstract;
  45.       procedure WriteFormattedPrefix(Stream: TStream);
  46.       procedure WriteFormattedSuffix(Stream: TStream);
  47.     public
  48.       constructor Create;
  49.       function CloneNode(RecurseChildren: Boolean = False): TXmlDNode;
  50.           virtual; abstract;
  51.       procedure AppendChild(NewNode: TXmlDNode); virtual;
  52.       function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
  53.           TXmlDNode; virtual;
  54.       procedure InsertBefore(NewNode: TXmlDNode; ThisNode: TXmlDNode);
  55.       function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; virtual;
  56.       function HasChildNodes: Boolean; virtual;
  57.       property FirstChild: TXmlDNode read GetFirstChild;
  58.       property LastChild: TXmlDNode read GetLastChild;
  59.       property PreviousSibling: TXmlDNode read FPreviousSibling;
  60.       property NextSibling: TXmlDNode read FNextSibling;
  61.       property ParentNode: TXmlDStructureNode read FParentNode;
  62.       property OwnerDocument: TXmlDDocument read GetOwnerDocument;
  63.       property NodeName: TXmlName read GetNodeName write SetNodeName;
  64.       property NodeType: TXmlNodeType read FNodeType;
  65.       property NodeValue: String read GetNodeValue write SetNodeValue;
  66.       property Level: Integer read GetLevel;
  67.   end;
  68.  
  69.   TXmlDStructureNode = class(TXmlDNode)
  70.     private
  71.       FFirstChild:      TXmlDNode;
  72.       FLastChild:       TXmlDNode;
  73.     protected
  74.       procedure CloneChildren(FromNode: TXmlDStructureNode);
  75.       procedure WriteChildrenToStream(Stream: TStream;
  76.           FormattedForPrint:Boolean);
  77.     public
  78.       destructor Destroy; override;
  79.       function GetFirstChild: TXmlDNode; override;
  80.       function GetLastChild: TXmlDNode; override;
  81.       procedure AppendChild(NewNode: TXmlDNode); override;
  82.       function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
  83.           TXmlDNode; override;
  84.       function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; override;
  85.       function HasChildNodes: Boolean; override;
  86.     end;
  87.  
  88.   TXmlDContentNode = class(TXmlDNode)
  89.     private
  90.       FValue: String;
  91.     protected
  92.       function GetNodeValue: String; override;
  93.       procedure SetNodeValue(const Value: String); override;
  94.   end;
  95.  
  96.   TXmlDDocument = class(TXmlDStructureNode)
  97.     private
  98.       FDocumentElement: TXmlDElement;
  99.       FDocumentTypeDefinition: String;
  100.     protected
  101.       procedure WriteToStream(Stream: TStream;
  102.           FormattedForPrint: Boolean); override;
  103.     public
  104.       constructor Create;
  105.       function CloneNode(RecurseChildren: Boolean): TXmlDNode;
  106.           override;
  107.       procedure Clear;
  108.       procedure AppendChild(NewNode: TXmlDNode); override;
  109.       function ReplaceChild(NewNode: TXmlDNode; OldNode: TXmlDNode):
  110.           TXmlDNode; override;
  111.       procedure InsertBefore(NewNode: TXmlDNode; ThisNode: TXmlDNode);
  112.       function RemoveChild(ThisNode: TXmlDNode): TXmlDNode; override;
  113.       function CreateCDATASection(const Text: String):
  114.           TXmlDCDATASection;
  115.       function CreateComment(const Text: String): TXmlDComment;
  116.       function CreateElement(const TagName: TXmlName): TXmlDElement;
  117.           overload;
  118.       function CreateElement(const TagName: TXmlName;
  119.           const Data: String): TXmlDElement; overload;
  120.       function CreateElement(const TagName: TXmlName;
  121.           const Data: String; const AttrName: TXmlName;
  122.           const AttrValue: String): TXmlDElement; overload;
  123.       function CreateElement(const TagName: TXmlName;
  124.           const Data: String; const AttrNames: array of TXmlName;
  125.           const AttrValues: array of String): TXmlDElement; overload;
  126.       function CreateTextNode(const Text: String): TXmlDText;
  127.       procedure SaveToStream(Stream: TStream;
  128.           FormattedForPrint: Boolean = False);
  129.       procedure SaveToFile(const FileName: String;
  130.           FormattedForPrint: Boolean = False);
  131.       property DocumentElement: TXmlDElement read FDocumentElement;
  132.       property DocumentTypeDefinition: String
  133.           read FDocumentTypeDefinition write FDocumentTypeDefinition;
  134.   end;
  135.  
  136.   TXmlDElement = class(TXmlDStructureNode)
  137.     private
  138.       FNodeName:        TXmlName;
  139.       FAttrList:        TXmlDAttrList;
  140.     protected
  141.       function GetNodeName: TXmlName; override;
  142.       procedure SetNodeName(const Value: TXmlName); override;
  143.       procedure WriteToStream(Stream: TStream;
  144.           FormattedForPrint: Boolean); override;
  145.     public
  146.       constructor Create;
  147.       destructor Destroy; override;
  148.       function CloneNode(RecurseChildren: Boolean): TXmlDNode;
  149.           override;
  150.       property AttrList: TXmlDAttrList read FAttrList;
  151.   end;
  152.  
  153.   TXmlDText = class(TXmlDContentNode)
  154.   protected
  155.     procedure WriteToStream(Stream: TStream;
  156.         FormattedForPrint: Boolean); override;
  157.   public
  158.     constructor Create;
  159.     function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
  160.   end;
  161.  
  162.   TXmlDComment = class(TXmlDContentNode)
  163.   protected
  164.     procedure WriteToStream(Stream: TStream;
  165.         FormattedForPrint: Boolean); override;
  166.   public
  167.     constructor Create;
  168.     function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
  169.   end;
  170.  
  171.   TXmlDCDATASection = class(TXmlDContentNode)
  172.   protected
  173.     procedure WriteToStream(Stream: TStream;
  174.         FormattedForPrint: Boolean); override;
  175.   public
  176.     constructor Create;
  177.     function CloneNode(RecurseChildren: Boolean): TXmlDNode; override;
  178.   end;
  179.  
  180.   TXmlDAttrList = class(TPersistent)
  181.   private
  182.     List:     TStringList;
  183.   protected
  184.     function GetCount: Integer;
  185.     function GetValues(const Name: TXmlName): String;
  186.     function GetNames(Index: Integer): TXmlName;
  187.     procedure SetValues(const Name: TXmlName; const Value: String);
  188.     procedure WriteToStream(Stream: TStream);
  189.   public
  190.     constructor Create;
  191.     destructor Destroy; override;
  192.     procedure Assign(Source: TPersistent); override;
  193.     procedure Clear;
  194.     property Count: Integer read GetCount;
  195.     property Names[Index: Integer]: TXmlName read GetNames;
  196.     property Values[const Name: TXmlName]: String read GetValues
  197.         write SetValues; default;
  198.   end;
  199.  
  200. implementation
  201.  
  202. { TXmlDNode }
  203.  
  204. procedure TXmlDNode.AppendChild(NewNode: TXmlDNode);
  205. begin
  206.   raise EXmlDError.Create('AppendChild operation requested on ' +
  207.       'invalid node type');
  208. end;
  209.  
  210. constructor TXmlDNode.Create;
  211. begin
  212.   inherited Create;
  213. end;
  214.  
  215. function TXmlDNode.GetFirstChild: TXmlDNode;
  216. begin
  217.   Result := nil;
  218. end;
  219.  
  220. function TXmlDNode.GetLastChild: TXmlDNode;
  221. begin
  222.   Result := nil;
  223. end;
  224.  
  225. function TXmlDNode.GetLevel: Integer;
  226. var
  227.   ParentNode: TXmlDStructureNode;
  228. begin
  229.   Result := 0;
  230.   ParentNode := FParentNode;
  231.   while ParentNode <> nil do
  232.   begin
  233.     Inc(Result);
  234.     ParentNode := ParentNode.FParentNode;
  235.   end;
  236. end;
  237.  
  238. function TXmlDNode.GetNodeName: TXmlName;
  239. begin
  240.   Result := XmlNodeNames[FNodeType];
  241. end;
  242.  
  243. function TXmlDNode.GetNodeValue: String;
  244. begin
  245.   Result := '';
  246. end;
  247.  
  248. function TXmlDNode.GetOwnerDocument: TXmlDDocument;
  249. var
  250.   ParentNode: TXmlDStructureNode;
  251. begin
  252.   ParentNode := FParentNode;
  253.   while ParentNode <> nil do
  254.     ParentNode := ParentNode.FParentNode;
  255.   Result := ParentNode as TXmlDDocument;
  256. end;
  257.  
  258. function TXmlDNode.HasChildNodes: Boolean;
  259. begin
  260.   Result := False;
  261. end;
  262.  
  263. procedure TXmlDNode.InsertBefore(NewNode, ThisNode: TXmlDNode);
  264. begin
  265.   if ThisNode = FParentNode.FFirstChild then
  266.     FParentNode.FFirstChild := NewNode;
  267.   if ThisNode.FPreviousSibling <> nil then
  268.     ThisNode.FPreviousSibling.FNextSibling := NewNode;
  269.   NewNode.FPreviousSibling := ThisNode.FPreviousSibling;
  270.   ThisNode.FPreviousSibling := NewNode;
  271.   NewNode.FNextSibling := ThisNode;
  272. end;
  273.  
  274. function TXmlDNode.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
  275. begin
  276.   raise EXmlDError.Create('RemoveChild operation requested on ' +
  277.       'invalid node type');
  278. end;
  279.  
  280. function TXmlDNode.ReplaceChild(NewNode, OldNode: TXmlDNode): TXmlDNode;
  281. begin
  282.   raise EXmlDError.Create('ReplaceChild operation requested on ' +
  283.       'invalid node type');
  284. end;
  285.  
  286. procedure TXmlDNode.SetNodeName(const Value: TXmlName);
  287. begin
  288. end;
  289.  
  290. procedure TXmlDNode.SetNodeValue(const Value: String);
  291. begin
  292. end;
  293.  
  294. procedure TXmlDNode.WriteFormattedPrefix(Stream: TStream);
  295. var
  296.   S:  String;
  297. begin
  298.   S := StringOfChar(' ', (Level - 1) * 2);
  299.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  300. end;
  301.  
  302. procedure TXmlDNode.WriteFormattedSuffix(Stream: TStream);
  303. const
  304.   CRLF:  String[3] = #13#10;
  305. begin
  306.   Stream.WriteBuffer(CRLF[1], 2);
  307. end;
  308.  
  309. { TXmlDStructureNode }
  310.  
  311. procedure TXmlDStructureNode.AppendChild(NewNode: TXmlDNode);
  312. begin
  313.   NewNode.FParentNode := Self;
  314.   if FFirstChild = nil then
  315.   begin
  316.     FFirstChild := NewNode;
  317.     FLastChild := NewNode;
  318.   end
  319.   else
  320.   begin
  321.     FLastChild.FNextSibling := NewNode;
  322.     NewNode.FPreviousSibling := FLastChild;
  323.     FLastChild := NewNode;
  324.   end;
  325. end;
  326.  
  327. procedure TXmlDStructureNode.CloneChildren(FromNode: TXmlDStructureNode);
  328. var
  329.   N:  TXmlDNode;
  330. begin
  331.   N := FromNode.FFirstChild;
  332.   while N <> nil do
  333.   begin
  334.     AppendChild(N.CloneNode(True));
  335.     N := N.NextSibling;
  336.   end;
  337. end;
  338.  
  339. destructor TXmlDStructureNode.Destroy;
  340. var
  341.   Node: TXmlDNode;
  342.   NextNode: TXmlDNode;
  343. begin
  344.   Node := FFirstChild;
  345.   while (Node <> nil) do
  346.   begin
  347.     NextNode := Node.FNextSibling;
  348.     Node.Free;
  349.     Node := NextNode;
  350.   end;
  351.   inherited Destroy;
  352. end;
  353.  
  354. function TXmlDStructureNode.GetFirstChild: TXmlDNode;
  355. begin
  356.   Result := FFirstChild;
  357. end;
  358.  
  359. function TXmlDStructureNode.GetLastChild: TXmlDNode;
  360. begin
  361.   Result := FLastChild;
  362. end;
  363.  
  364. function TXmlDStructureNode.HasChildNodes: Boolean;
  365. begin
  366.   Result := FFirstChild <> nil;
  367. end;
  368.  
  369. function TXmlDStructureNode.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
  370. begin
  371.   Result := FFirstChild;
  372.   while ((Result <> nil) and (Result <> ThisNode)) do
  373.     Result := Result.FNextSibling;
  374.   if Result <> nil then
  375.   begin
  376.     if FFirstChild = FLastChild then
  377.     begin
  378.       FFirstChild := nil;
  379.       FLastChild := nil;
  380.     end
  381.     else if Result = FFirstChild then
  382.     begin
  383.       FFirstChild := FFirstChild.FNextSibling;
  384.       FFirstChild.FPreviousSibling := nil;
  385.     end
  386.     else if Result = FLastChild then
  387.     begin
  388.       FLastChild := FLastChild.FPreviousSibling;
  389.       FLastChild.FNextSibling := nil;
  390.     end
  391.     else
  392.     begin
  393.       Result.FPreviousSibling.FNextSibling := Result.FNextSibling;
  394.       Result.FNextSibling.FPreviousSibling := Result.FPreviousSibling;
  395.     end;
  396.     Result.FNextSibling := nil;
  397.     Result.FPreviousSibling := nil;
  398.     Result.FParentNode := nil;
  399.   end;
  400. end;
  401.  
  402. function TXmlDStructureNode.ReplaceChild(NewNode,
  403.   OldNode: TXmlDNode): TXmlDNode;
  404. var
  405.   NextNode: TXmlDNode;
  406. begin
  407.   if OldNode = FLastChild then
  408.   begin
  409.     Result := RemoveChild(OldNode);
  410.     AppendChild(NewNode);
  411.   end
  412.   else
  413.   begin
  414.     NextNode := OldNode.FNextSibling;
  415.     Result := RemoveChild(OldNode);
  416.     InsertBefore(NewNode, NextNode);
  417.   end;
  418. end;
  419.  
  420. procedure TXmlDStructureNode.WriteChildrenToStream(Stream: TStream;
  421.     FormattedForPrint: Boolean);
  422. var
  423.   N:  TXmlDNode;
  424. begin
  425.   N := FFirstChild;
  426.   while (N <> nil) do
  427.   begin
  428.     N.WriteToStream(Stream, FormattedForPrint);
  429.     N := N.FNextSibling;
  430.   end;
  431. end;
  432.  
  433. { TXmlDContentNode }
  434.  
  435. function TXmlDContentNode.GetNodeValue: String;
  436. begin
  437.   Result := FValue;
  438. end;
  439.  
  440. procedure TXmlDContentNode.SetNodeValue(const Value: String);
  441. begin
  442.   FValue := Value;
  443. end;
  444.  
  445. { TXmlDDocument }
  446.  
  447. procedure TXmlDDocument.AppendChild(NewNode: TXmlDNode);
  448. begin
  449.   if NewNode.NodeType = xntElement then
  450.   begin
  451.     if FDocumentElement <> nil then
  452.       raise EXmlDError.Create('Second document element add attempted');
  453.     FDocumentElement := TXmlDElement(NewNode);
  454.   end;
  455.   inherited AppendChild(NewNode);
  456. end;
  457.  
  458. procedure TXmlDDocument.Clear;
  459. var
  460.   Node: TXmlDNode;
  461.   NextNode: TXmlDNode;
  462. begin
  463.   Node := FFirstChild;
  464.   while (Node <> nil) do
  465.   begin
  466.     NextNode := Node.FNextSibling;
  467.     Node.Free;
  468.     Node := NextNode;
  469.   end;
  470.   FFirstChild := nil;
  471.   FLastChild := nil;
  472.   FDocumentElement := nil;
  473. end;
  474.  
  475. function TXmlDDocument.CloneNode(RecurseChildren: Boolean): TXmlDNode;
  476. var
  477.   Clone: TXmlDDocument;
  478. begin
  479.   Clone := TXmlDDocument.Create;
  480.   if RecurseChildren then
  481.     Clone.CloneChildren(Self);
  482.   Result := Clone;
  483. end;
  484.  
  485. constructor TXmlDDocument.Create;
  486. begin
  487.   inherited Create;
  488.   FNodeType := xntDocument;
  489. end;
  490.  
  491. function TXmlDDocument.CreateCDATASection(
  492.   const Text: String): TXmlDCDATASection;
  493. begin
  494.   Result := TXmlDCDATASection.Create;
  495.   Result.NodeValue := Text;
  496. end;
  497.  
  498. function TXmlDDocument.CreateComment(const Text: String): TXmlDComment;
  499. begin
  500.   Result := TXmlDComment.Create;
  501.   Result.NodeValue := Text;
  502. end;
  503.  
  504. function TXmlDDocument.CreateElement(
  505.   const TagName: TXmlName): TXmlDElement;
  506. begin
  507.   Result := TXmlDElement.Create;
  508.   Result.NodeName := TagName;
  509. end;
  510.  
  511. function TXmlDDocument.CreateElement(
  512.   const TagName: TXmlName; const Data: String): TXmlDElement;
  513. begin
  514.   Result := TXmlDElement.Create;
  515.   Result.NodeName := TagName;
  516.   if Data <> '' then
  517.     Result.AppendChild(OwnerDocument.CreateTextNode(Data));
  518. end;
  519.  
  520. function TXmlDDocument.CreateElement(const TagName: TXmlName;
  521.   const Data: String; const AttrName: TXmlName;
  522.   const AttrValue: String): TXmlDElement;
  523. begin
  524.   Result := TXmlDElement.Create;
  525.   Result.NodeName := TagName;
  526.   if AttrName <> '' then
  527.     Result.FAttrList.Values[AttrName] := AttrValue;
  528.   if Data <> '' then
  529.     Result.AppendChild(OwnerDocument.CreateTextNode(Data));
  530. end;
  531.  
  532. function TXmlDDocument.CreateElement(const TagName: TXmlName;
  533.   const Data: String; const AttrNames: array of TXmlName;
  534.   const AttrValues: array of String): TXmlDElement;
  535. var
  536.   I:  Integer;
  537. begin
  538.   if (Low(AttrNames) <> Low(AttrValues)) or
  539.       (High(AttrNames) <> High(AttrValues)) then
  540.     raise EXmlDError.Create('Invalid CreateElement call');
  541.   Result := TXmlDElement.Create;
  542.   Result.NodeName := TagName;
  543.   for I := Low(AttrNames) to High(AttrNames) do
  544.     if AttrNames[I] <> '' then
  545.       Result.FAttrList.Values[AttrNames[I]] := AttrValues[I];
  546.   if Data <> '' then
  547.     Result.AppendChild(OwnerDocument.CreateTextNode(Data));
  548. end;
  549.  
  550. function TXmlDDocument.CreateTextNode(const Text: String): TXmlDText;
  551. begin
  552.   Result := TXmlDText.Create;
  553.   Result.NodeValue := Text;
  554. end;
  555.  
  556. procedure TXmlDDocument.InsertBefore(NewNode, ThisNode: TXmlDNode);
  557. begin
  558.   if NewNode.NodeType = xntElement then
  559.   begin
  560.     if FDocumentElement <> nil then
  561.       raise EXmlDError.Create('Second document element add attempted');
  562.     FDocumentElement := TXmlDElement(NewNode);
  563.   end;
  564.   inherited InsertBefore(NewNode, ThisNode);
  565. end;
  566.  
  567. function TXmlDDocument.RemoveChild(ThisNode: TXmlDNode): TXmlDNode;
  568. begin
  569.   if ThisNode = FDocumentElement then
  570.     FDocumentElement := nil;
  571.   Result := inherited RemoveChild(ThisNode);
  572. end;
  573.  
  574. function TXmlDDocument.ReplaceChild(NewNode,
  575.   OldNode: TXmlDNode): TXmlDNode;
  576. begin
  577.   if OldNode = FDocumentElement then
  578.     FDocumentElement := nil;
  579.   if NewNode.NodeType = xntElement then
  580.     FDocumentElement := TXmlDElement(NewNode);
  581.   Result := inherited ReplaceChild(NewNode, OldNode);
  582. end;
  583.  
  584. procedure TXmlDDocument.SaveToFile(const FileName: String;
  585.     FormattedForPrint: Boolean);
  586. var
  587.   Stream: TStream;
  588. begin
  589.   Stream := TFileStream.Create(FileName, fmCreate);
  590.   try
  591.     SaveToStream(Stream);
  592.   finally
  593.     Stream.Free;
  594.   end;
  595. end;
  596.  
  597. procedure TXmlDDocument.SaveToStream(Stream: TStream;
  598.     FormattedForPrint: Boolean = False);
  599. begin
  600.   WriteToStream(Stream, FormattedForPrint);
  601. end;
  602.  
  603. procedure TXmlDDocument.WriteToStream(Stream: TStream;
  604.     FormattedForPrint: Boolean);
  605. var
  606.   S:  String;
  607. begin
  608.   S := '<?xml version="1.0"?>';
  609.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  610.   if FormattedForPrint then
  611.     WriteFormattedSuffix(Stream);
  612.   if FDocumentTypeDefinition <> '' then
  613.   begin
  614.     S := '<!DOCTYPE ';
  615.     if DocumentElement<> nil then
  616.       S := S + DocumentElement.NodeName + ' ';
  617.     S := S + FDocumentTypeDefinition + '>';
  618.     Stream.WriteBuffer(Pointer(S)^, Length(S));
  619.     if FormattedForPrint then
  620.       WriteFormattedSuffix(Stream);
  621.   end;
  622.   WriteChildrenToStream(Stream, FormattedForPrint);
  623. end;
  624.  
  625. { TXmlDElement }
  626.  
  627. function TXmlDElement.CloneNode(RecurseChildren: Boolean): TXmlDNode;
  628. var
  629.   Clone:  TXmlDElement;
  630. begin
  631.   Clone := TXmlDElement.Create;
  632.   Clone.FNodeName := FNodeName;
  633.   Clone.FAttrList.Assign(FAttrList);
  634.   if RecurseChildren then
  635.     Clone.CloneChildren(Self);
  636.   Result := Clone;
  637. end;
  638.  
  639. constructor TXmlDElement.Create;
  640. begin
  641.   inherited Create;
  642.   FAttrList := TXmlDAttrList.Create;
  643.   FNodeType := xntElement;
  644. end;
  645.  
  646. destructor TXmlDElement.Destroy;
  647. begin
  648.   FAttrList.Free;
  649.   inherited Destroy;
  650. end;
  651.  
  652. function TXmlDElement.GetNodeName: TXmlName;
  653. begin
  654.   Result := FNodeName;
  655. end;
  656.  
  657. procedure TXmlDElement.SetNodeName(const Value: TXmlName);
  658. begin
  659.   FNodeName := Value;
  660. end;
  661.  
  662. procedure TXmlDElement.WriteToStream(Stream: TStream;
  663.     FormattedForPrint: Boolean);
  664. var
  665.   S:  String;
  666.   Formatted: Boolean;
  667. begin
  668.   Formatted := FormattedForPrint;
  669.   if Formatted then
  670.   begin
  671.     if (FFirstChild <> nil) and (FFirstChild = FLastChild) and
  672.         (FFirstChild.NodeType = xntText) and
  673.         (Length(FFirstChild.NodeValue) < 48) then
  674.       Formatted := False;
  675.     WriteFormattedPrefix(Stream);
  676.   end;
  677.   S := '<' + FNodeName;
  678.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  679.   if FAttrList.Count > 0 then
  680.     FAttrList.WriteToStream(Stream);
  681.   if FFirstChild <> nil then
  682.   begin
  683.     S := '>';
  684.     Stream.WriteBuffer(Pointer(S)^, 1);
  685.     if Formatted then
  686.       WriteFormattedSuffix(Stream);
  687.   end;
  688.   if FFirstChild = nil then
  689.     S := '/>'
  690.   else
  691.   begin
  692.     WriteChildrenToStream(Stream, Formatted);
  693.     if Formatted then
  694.       WriteFormattedPrefix(Stream);
  695.     S := '</' + FNodeName + '>';
  696.   end;
  697.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  698.   if FormattedForPrint then
  699.     WriteFormattedSuffix(Stream);
  700. end;
  701.  
  702. { TXmlDText }
  703.  
  704. function TXmlDText.CloneNode(RecurseChildren: Boolean): TXmlDNode;
  705. begin
  706.   Result := TXmlDText.Create;
  707.   Result.NodeValue := NodeValue;
  708. end;
  709.  
  710. constructor TXmlDText.Create;
  711. begin
  712.   inherited Create;
  713.   FNodeType := xntText;
  714. end;
  715.  
  716. procedure TXmlDText.WriteToStream(Stream: TStream;
  717.     FormattedForPrint: Boolean);
  718. begin
  719.   if FormattedForPrint then
  720.     WriteFormattedPrefix(Stream);
  721.   Stream.WriteBuffer(Pointer(FValue)^, Length(FValue));
  722.   if FormattedForPrint then
  723.     WriteFormattedSuffix(Stream);
  724. end;
  725.  
  726. { TXmlDComment }
  727.  
  728. function TXmlDComment.CloneNode(RecurseChildren: Boolean): TXmlDNode;
  729. begin
  730.   Result := TXmlDComment.Create;
  731.   Result.NodeValue := NodeValue;
  732. end;
  733.  
  734. constructor TXmlDComment.Create;
  735. begin
  736.   inherited Create;
  737.   FNodeType := xntComment;
  738. end;
  739.  
  740. procedure TXmlDComment.WriteToStream(Stream: TStream;
  741.   FormattedForPrint: Boolean);
  742. var
  743.   S:  String;
  744. begin
  745.   if FormattedForPrint then
  746.     WriteFormattedPrefix(Stream);
  747.   S := '<!--' + FValue + '-->';
  748.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  749.   if FormattedForPrint then
  750.     WriteFormattedSuffix(Stream);
  751. end;
  752.  
  753. { TXmlCDATASection }
  754.  
  755. function TXmlDCDATASection.CloneNode(RecurseChildren: Boolean): TXmlDNode;
  756. begin
  757.   Result := TXmlDCDATASection.Create;
  758.   Result.NodeValue := NodeValue;
  759. end;
  760.  
  761. constructor TXmlDCDATASection.Create;
  762. begin
  763.   inherited Create;
  764.   FNodeType := xntCDATASection;
  765. end;
  766.  
  767. procedure TXmlDCDATASection.WriteToStream(Stream: TStream;
  768.     FormattedForPrint: Boolean);
  769. var
  770.   S:  String;
  771. begin
  772.   if FormattedForPrint then
  773.     WriteFormattedPrefix(Stream);
  774.   S := '<![CDATA[' + FValue + ']]>';
  775.   Stream.WriteBuffer(Pointer(S)^, Length(S));
  776.   if FormattedForPrint then
  777.     WriteFormattedSuffix(Stream);
  778. end;
  779.  
  780. { TXmlDAttrList }
  781.  
  782. procedure TXmlDAttrList.Assign(Source: TPersistent);
  783. begin
  784.   if Source is TXmlDAttrList then
  785.     List.Assign(TXmlDAttrList(Source).List);
  786. end;
  787.  
  788. procedure TXmlDAttrList.Clear;
  789. begin
  790.   List.Clear;
  791. end;
  792.  
  793. constructor TXmlDAttrList.Create;
  794. begin
  795.   inherited Create;
  796.   List := TStringList.Create;
  797. end;
  798.  
  799. destructor TXmlDAttrList.Destroy;
  800. begin
  801.   List.Free;
  802.   inherited Destroy;
  803. end;
  804.  
  805. function TXmlDAttrList.GetCount: Integer;
  806. begin
  807.   Result := List.Count;
  808. end;
  809.  
  810. function TXmlDAttrList.GetNames(Index: Integer): TXmlName;
  811. begin
  812.   Result := List.Names[Index];
  813. end;
  814.  
  815. function TXmlDAttrList.GetValues(const Name: TXmlName): String;
  816. begin
  817.   Result := List.Values[Name];
  818. end;
  819.  
  820. procedure TXmlDAttrList.SetValues(const Name: TXmlName;
  821.   const Value: String);
  822. begin
  823.   List.Values[Name] := Value;
  824. end;
  825.  
  826. procedure TXmlDAttrList.WriteToStream(Stream: TStream);
  827. var
  828.   I:  Integer;
  829.   J:  Integer;
  830.   S:  String;
  831. begin
  832.   for I := 0 to (List.Count - 1) do
  833.   begin
  834.     S := List[I];
  835.     J := Pos('=', S);
  836.     S := ' ' + Copy(S, 1, J) + '"' + Copy(S, J + 1, $7FFF) + '"';
  837.     Stream.WriteBuffer(Pointer(S)^, Length(S));
  838.   end;
  839. end;
  840.  
  841. end.
  842.